/********************************************************************************
 * Project Name		[JavaEE_Web]
 * File Name     	[Servlet04.java]
 * Creation Date 	[2015-01-01]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ********************************************************************************/
package _notes.servlet;

/**
 * 保存会话的技术 - Session
 * 
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 * 
 */
public final class Servlet04 {

	public void sessionConcept() {
		/**
		 * Session<br/>
		 * 服务器端技术, Session是一种会话跟踪机制, 该机制采用的是在服务器保持Http状态信息,
		 * 服务器使用一种类似于散列表的结构来保存信息<br/>
		 */

		/**
		 * Session是指一类用来在客户端与服务器端之间保持状态的解决方案, 有时候Session也用来指这种解决方案的存储结构<br/>
		 */
	}

	public void sessionProcess() {
		/**
		 * Session的使用过程<br/>
		 * 1: 当程序需要为某个客户端的请求创建一个Session时,
		 * 服务器首先检查这个客户端的请求里是否包含了一个Session标识[即SessionId]<br/>
		 * 
		 * 2: 如果已经包含一个SessionId则说明以前已经为此客户创建过Session,
		 * 服务器就按照SessionId把这个Session检索出来使用<br/>
		 * 
		 * 3. 如果检索不到, 可能会新建一个, 这种情况可能出现在服务端已经删除了该用户对应的Session对象,
		 * 但用户人为地在请求的URL后面附加上一个JSESSIONID的参数<br/>
		 * 
		 * 4. 如果客户请求不包含SessionId, 则为此客户创建一个Session并生成一个与此Session相关联的SessionId,
		 * 这个SessionId将在本次响应中返回给客户端保存<br/>
		 */
	}

	public void saveSession() {
		/**
		 * 保存Session的两种方式<br/>
		 * 1. 使用Cookie保存SessionID<br/>
		 * 在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器[默认使用Cookie来实现],
		 * 即Web服务器会创建一个名为JSESSIONID的Cookie[Session Cookie], 以区别Persistent
		 * cookies[通常所说的cookie], Session Cookie是存储于浏览器内存中的而并不是写到硬盘上的<br/>
		 * 
		 * 2. 禁用了Cookie时可以采用URL重写, 就是把SessionId附加在URL路径的后面<br/>
		 * 附加的方式有两种: 一种是作为URL路径的附加信息, 另一种是作为查询字符串附加在URL后面<br/>
		 */
	}

	public void lifeCycleOfSession() {
		/**
		 * Session的生命周期<br/>
		 * 1. 创建:<br/>
		 * 直到某个服务器端程序[如Servlet/JSP]调用HttpServletRequest对象的getSession(true)
		 * 或者getSession()方法时才会被创建<br/>
		 * 
		 * 下列情况Session不会被创建<br/>
		 * A. 若当前的JSP是客户端访问的Web应用的第一个资源且JSP的page指令的session属性值为false,
		 * 则服务器就不会为JSP创建HttpSession对象[session="false"表示当前 JSP页面禁用session隐含对象,
		 * 但可以使用其他的显式的HttpSession对象]<br/>
		 * B. 若当前JSP不是客户端访问的Web应用的第一个资源且其他页面已经创建了HttpSession对象,
		 * 则当前JSP页面会返回一个已经存在的HttpSession对象, 而不会创建一个新的HttpSession对象<br/>
		 * 
		 * 2. 销毁:<br/>
		 * A．服务器进程被停止<br/>
		 * B. 程序调用HttpSession.invalidate();<br/>
		 * C．距离上一次收到客户端发送的SessionID时间间隔超过了Session的最大有效时间[默认为30分钟]<br/>
		 * 
		 * 注意: 关闭浏览器只会使存储在客户端浏览器内存中的Session Cookie失效, 不会使服务器端的Session对象失效<br/>
		 * 
		 * 两种设置Session超时的方法<br/>
		 * 方式1, 编程式设置<br/>
		 * <code>
		 * HttpSession session = request.getSession();
		 * session.setMaxInactiveInterval(5); // 单位: 秒
		 * </code><br/>
		 * 方式2, 在web.xml中配置<br/>
		 * <code>
		 * <session-config>
		 *     <session-timeout>100</session-timeout> <!--单位: 分钟-->
		 * </session-config>
		 * </code>
		 */
	}

	public void sessionAPI() {
		/**
		 * javax.servlet.http.HttpSession<br/>
		 * getId(); 获得SessionID<br/>
		 * setMaxInactiveInterval(int seconds); 设置Session失效的时间<br/>
		 * getMaxInactiveInterval(); 获得Session的失效时间<br/>
		 * isNew(); 若请求返回的SessionID和当前程序获取的SessionID相同则这个HttpSession对象不是新建的<br/>
		 * invalidate(); 使当前Session失效<br/>
		 * setAttribute(String name, Object value);向Session中设置属性<br/>
		 * getAttribute(String name);从Session中获取指定name的属性<br/>
		 * removeAttribute(String name); 从Session中删除删除指定name的属性<br/>
		 * getAttributeNames();<br/>
		 * getCreationTime();<br/>
		 * getLastAccessedTime();<br/>
		 * getServletContext();<br/>
		 */

		/**
		 * javax.servlet.http.HttpServletRequest<br/>
		 * 
		 * request.getSession(boolean create); <br/>
		 * 1. create=false, 若没有和当前JSP页面关联的HttpSession对象, 则返回null; <br/>
		 * 2. create=true, 返回一个HttpSession对象, 若没有和当前页面关联的HttpSession对象,
		 * 服务器创建一个新的HttpSession对象, 若有, 则直接返回关联的HttpSession对象<br/>
		 * 
		 * request.isRequestedSessionIdValid();<br/>
		 * request.isRequestedSessionIdFromCookie();<br/>
		 * request.isRequestedSessionIdFromURL();<br/>
		 */

		/**
		 * javax.servlet.http.HttpServletResponse<br/>
		 * URL重写[将SessionID以参数形式附加在超链接的URL地址后面的技术称为URL重写]<br/>
		 * response.encodeRedirectURL(String URL) 用于对sendRedirect方法的URL进行重写<br/>
		 * response.encodeURL(String URL)用于对表单action和超链接的URL进行重写<br/>
		 */
	}

	public void resubmission() {
		/**
		 * 表单重复提交<br/>
		 * 
		 * 表单重复提交的场景<br/>
		 * 1. 当表单提交到Servlet, 而Servlet通过请求转发的方式响应另一个JSP页面, 此时地址栏还保留着Servlet的路径,
		 * 在该响应页面"刷新" <br/>
		 * 2. 在响应页面没有到达时重复点击"提交按钮"<br/>
		 * 3. 点击"返回", 再点击"提交"<br/>
		 * 
		 * 不是重复提交的场景<br/>
		 * 点击"返回", "刷新"原表单, 再"提交"<br/>
		 * 
		 * 解决方案<br/>
		 * Part1: 使用JavaScript disable提交按钮<br/>
		 * Part2: 在表单中做一个标记, 提交到Servlet时, 检查标记是否存在且是否和预定义的标记一致, 若一致, 则受理请求,
		 * 并销毁标记, 若不一致或没标记, 则直接响应提示信息: "请不要重复提交"<br/>
		 * 
		 * 1. 在原表单页面生成一个随机的Token<br/>
		 * 2. 在原表单页面将Token放入到Session属性中<br/>
		 * 3. 在原表单页面将Token放入到隐藏域中<br/>
		 * 4. 在目标Servlet中, 获取Session和隐藏域中的Token值<br/>
		 * 5. 比较两个值是否一致, 若一致, 则处理请求, 且把Session中的Token清除<br/>
		 * 6. 若不一致, 则直接响应信息: "重复提交"<br/>
		 * 
		 * 注意: 验证码验证的规则类似于表单提交<br/>
		 */
	}

	public void sessionPersistence() {
		/**
		 * Session的持久化<br/>
		 *
		 * 1. 在META-INF文件夹下新建context.xml<br/>
		 * 2. 配置持久化Session的信息<br/>
		 * <code>
		 * <Manager 
		 *     className="org.apache.catalina.session.PersistentManager"	<!-- Session持久化管理类, Tomcat将会通过定义的接口来应用该类生成的对象 -->  
		 *     debug="0"      												<!-- Session管理器的跟踪级别 -->
		 *     saveOnRestart="false"     									<!-- true|false, 服务器重启对Session的处理, 若为true, 则关闭前把有效的Session保存, 启动后重新载入 -->
		 *     maxActiveSession="-1"     									<!-- 可存放在内存中处于活动状态的Session的最大数量, -1表示不限制, 否则Session Manager会把超出该数量的Session对象转移到Session Store中 -->
		 *     minIdleSwap="-1"     										<!-- Session不活动的最短时间, 单位: 秒, 超过该时间, Session Manager可能会把该Session对象转移到Session Store中 -->
		 *     maxIdleSwap="-1"     										<!-- Session不活动的最长时间, 单位: 秒, 超过该时间, Session Manager会把该Session对象转移到Session Store中, 该Session对象将不在内存中 -->
		 *     maxIdleBackup="-1">  										<!-- Session不活动的最长时间, 单位: 秒, 超过该时间, Session Manager会把该Session对象备份到Session Store中, 该Session对象依然在内存中 -->
		 *     <Store 
		 *         className="org.apache.catalina.session.FileStore"  		<!-- 指定持久化到文件的类名 -->
		 *         directory="sns" />  										<!-- 指定Session文件保存的路径, 相对于当前Web应用 -->
		 *     <Store 
		 *         className="org.apache.catalina.session.JDBCStore" 		<!-- 指定持久化到数据库的类名 -->
		 *         driverName="com.mysql.jdbc.Driver"    					<!-- JDBC驱动类 -->
		 *         connectionURL="jdbc:mysql://localhost:3306/jdbc"    	    <!-- JDBC URL -->
		 *         connectionName="root"   									<!-- DB用户名 -->
		 *         connectionPassword="123456"    							<!-- DB密码 -->
		 *         sessionTable="tomcat_session"    						<!-- 存放Session信息的表名 -->
		 *         sessionIdCol="session_id"    							<!-- SessionId列名 -->
		 *         sessionDataCol="session_data"    						<!-- SessionDate列名 -->
		 *         sessionValidCol="session_valid"     						<!-- SessionValid列名 -->
		 *         sessionMaxInactiveCol="max_inactive"    					<!-- SessionMaxInactive列名 -->
		 *         sessionLastAccessedCol="last_access"    					<!-- SessionLastAccessed列名 -->
		 *         sessionAppCol="app_name"     							<!-- SessionApp列名 -->
		 *         checkInterval="60" 										<!-- 检查间隔时间, 单位: 秒 -->
		 *         debug="99" />											<!-- debug级别, 值越大输出内容越精确 -->
		 * </Manager>
		 * </code><br/>
		 */

		/**
		 * Session Table<br/>
		 * <code>
		 * CREATE TABLE tomcat_session(
		 *     session_id VARCHAR(200) PRIMARY KEY NOT NULL,
		 *     session_data BLOB NOT NULL,
		 *     session_valid VARCHAR(1) NOT NULL,
		 *     max_inactive DECIMAL(20,0) NOT NULL,
		 *     last_access DECIMAL(20,0) NOT NULL,
		 *     app_name VARCHAR(200) NOT NULL
		 * )
		 * </code>
		 */
	}
}
